package ast;

/**
 * <code>SimpleVisitor</code> Simple implementation of a Visitor It traverses
 * the tree printing on stdout what it finds in the nodes of the AST The input
 * program is therefore reproduced on stdout without indentation
 */
public class SimpleVisitor implements Visitor
{

	public Object visit(List n)
	{
		n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		return null;
	}

	public Object visit(AddNode n)
	{
		n.left.accept(this);
		System.out.print(" + ");
		n.right.accept(this);
		return null;
	}

	public Object visit(TimesNode n)
	{
		n.left.accept(this);
		System.out.print(" * ");
		n.right.accept(this);
		return null;
	}

	public Object visit(DivideNode n)
	{
		n.left.accept(this);
		System.out.print(" / ");
		n.right.accept(this);
		return null;
	}

	public Object visit(MinusNode n)
	{
		n.left.accept(this);
		System.out.print(" - ");
		n.right.accept(this);
		return null;
	}

	public Object visit(RealNumNode n)
	{
		System.out.print(n.value);
		return null;
	}

	public Object visit(LeNode n)
	{
		n.left.accept(this);
		System.out.print(" < ");
		n.right.accept(this);
		return null;
	}

	public Object visit(LeqNode n)
	{
		n.left.accept(this);
		System.out.print(" <= ");
		n.right.accept(this);
		return null;
	}

	public Object visit(GeNode n)
	{
		n.left.accept(this);
		System.out.print(" > ");
		n.right.accept(this);
		return null;
	}

	public Object visit(GeqNode n)
	{
		n.left.accept(this);
		System.out.print(" >= ");
		n.right.accept(this);
		return null;
	}

	public Object visit(ExpNode n)
	{
		n.left.accept(this);
		System.out.print("^");
		n.right.accept(this);
		return null;
	}

	public Object visit(OrNode n)
	{
		n.left.accept(this);
		System.out.print(" || ");
		n.right.accept(this);
		return null;
	}

	public Object visit(AndNode n)
	{
		n.left.accept(this);
		System.out.print(" && ");
		n.right.accept(this);
		return null;
	}

	public Object visit(EqNode n)
	{
		n.left.accept(this);
		System.out.print(" == ");
		n.right.accept(this);
		return null;
	}

	public Object visit(NeqNode n)
	{
		n.left.accept(this);
		System.out.print(" != ");
		n.right.accept(this);
		return null;
	}

	public Object visit(InNode n)
	{
		n.left.accept(this);
		System.out.print(" in ");
		n.right.accept(this);
		return null;
	}

	public Object visit(CharListNode n)
	{
		System.out.print("\"" + n.value + "\"");
		return null;
	}

	public Object visit(IntNumNode n)
	{
		System.out.print(n.value.intValue());
		return null;
	}

	public Object visit(Node n)
	{
		n.left.accept(this);
		n.right.accept(this);
		return null;
	}

	public Object visit(ExprNode n)
	{
		if (n.left != null)
			n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		return null;
	}

	public Object visit(BooleanNode n)
	{
		if (n.value)
			System.out.print("T");
		else
			System.out.print("F");
		return null;
	}

	public Object visit(AssignNode n)
	{
		n.var.accept(this);
		System.out.print(" = ");
		n.left.accept(this);
		System.out.println(";");
		return null;
	}

	// *** NEED TO BE CHECKED ***
	public Object visit(IfNode n)
	{
		System.out.print("if ( ");
		n.e.accept(this);
		System.out.print(" )");
		if (n.left != null)
		{
			n.left.accept(this);
		}
		System.out.println("else");
		if (n.right != null)
		{
			n.right.accept(this);
		}
		return null;
	}

	public Object visit(ReturnStmtNode n)
	{
		System.out.print("return ");
		if (n.left != null)
			n.left.accept(this);
		System.out.print(";");
		return null;
	}

	public Object visit(VarNode n)
	{
		if (n.left == null)
		{
			System.out.print(n.id);
		} else if (n.left.getClass() == VarNode.class
				|| n.left.getClass() == CallVarNode.class)
		{
			n.left.accept(this);
			System.out.print(".");
			System.out.print(n.id);
		}
		return null;
	}

	public Object visit(ParamNode n)
	{
		System.out.print(n.type + " " + n.id);
		return null;
	}

	public Object visit(BodyNode n)
	{
		System.out.print(" {\n");
		if (n.vardecs != null)
			n.vardecs.accept(this);
		if (n.left != null)
			n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		System.out.print(" }\n");
		return null;
	}

	public Object visit(CallVarExprNode n)
	{
		n.left.accept(this);
		return null;
	}

	public Object visit(CallVarNode n)
	{
		if (n.left != null)
		{
			n.left.accept(this);
			System.out.print(".");
		}
		System.out.print(n.id);
		System.out.print(" (");
		if (n.left != null)
			n.left.accept(this);
		System.out.print(") ");
		return null;
	}

	public Object visit(CallVarStmtNode n)
	{
		n.left.accept(this);
		System.out.println(";");
		return null;
	}

	public Object visit(ClassDecNode n)
	{
		System.out.print("class ");

		System.out.print(n.id);

		System.out.print(" {\n");

		if (n.left != null)
			n.left.accept(this);

		System.out.print("}\n");
		return null;
	}

	public Object visit(ClassDefNode n)
	{
		if (n.instList != null)
		{
			n.instList.accept(this);
		}
		if (n.left != null)
		{
			n.left.accept(this);
		}
		return null;
	}

	public Object visit(InstVarDecNode n)
	{
		System.out.print(n.access);
		n.left.accept(this);
		return null;
	}

	// *** NOT SURE ABOUT THIS ***
	public Object visit(LenNode n)
	{
		System.out.print("len(");
		n.left.accept(this);
		System.out.print(")");
		return null;
	}

	public Object visit(MainProgramNode n)
	{
		System.out.print("START  {\n");
		if (n.declist != null)
			n.declist.accept(this);
		if (n.left != null)
			n.left.accept(this);
		System.out.print(" }\n");
		return null;
	}

	public Object visit(MethodBodyNode n)
	{
		System.out.print(" {\n");
		if (n.vardeclist != null)
			n.vardeclist.accept(this);
		if (n.left != null)
			n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		System.out.print("\n  }\n");
		return null;
	}

	public Object visit(MethodDecNode n)
	{
		System.out.print(n.access);
		if (n.type != null)
		{
			System.out.print(" " + n.type);
		} else
		{
			System.out.print(" void ");
		}
		System.out.print(n.id);
		if (n.params != null)
		{
			// System.out.print("(");
			n.params.accept(this);
			// System.out.print(")");
		}
		if (n.params == null)
			System.out.println("()");
		if (n.left != null)
		{
			n.left.accept(this);
		}
		return null;
	}

	public Object visit(NotinNode n)
	{
		n.left.accept(this);
		System.out.println(" !contains ");
		n.right.accept(this);
		return null;
	}

	public Object visit(NotNode n)
	{
		System.out.print("!");
		n.left.accept(this);
		return null;
	}

	public Object visit(ObjTypeDecNode n)
	{
		System.out.println(" newobj " + n.type + " " + n.id + ";");
		return null;
	}

	public Object visit(RepeatNode n)
	{
		if (n.left != null)
			System.out.print("REPEAT");
		
		n.left.accept(this);
		System.out.print("UNTIL");
		System.out.print(" (");
		n.right.accept(this);
		System.out.print(" )\n");
		return null;
	}

	public Object visit(VarExprNode n)
	{
		n.left.accept(this);
		return null;
	}

	public Object visit(BasicTypeDecNode n)
	{
		System.out.print(" " + n.type + n.id);
		if (n.left != null)
		{
			System.out.print(" = ");
			n.left.accept(this);
		}

		System.out.println(";");
		return null;
	}

	public Object visit(ParamlistNode n)
	{
		System.out.print(",");
		n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		return null;
	}

	public Object visit(FormalparamNode n)
	{

		System.out.print("(");
		n.left.accept(this);
		if (n.right != null)
			n.right.accept(this);
		System.out.print(")");
		return null;
	}

	public Object visit(ParanExprNode n)
	{
		System.out.print("(");
		n.en.accept(this);
		System.out.print(")");
		return null;
	}

	public Object visit(RootNode n) {
		n.left.accept(this);
		if(n.right != null) {
			n.right.accept(this);
		}
		return null;
	}

	public Object visit(TypeDecNode n) {
		// TODO Auto-generated method stub
		return null;
	}

}